from typing import Annotated, List

from fastapi import APIRouter, Body, Depends, Path, Query, Request

from app.api.deps import CurrentUserDep, RoleServiceDep, require_permission
from app.core import settings
from app.exceptions.base import AppException
from app.models.system import SysUser
from app.schemas.base import Pagination, Response
from app.schemas.option import IntOption
from app.schemas.role import RoleForm, RolePageVO
from app.utils.log_api_call import log

router = APIRouter(prefix=f"{settings.API_V1_STR}/roles", tags=["03.角色接口"])


@router.get(
    "/page", response_model=Response[Pagination[RolePageVO]], summary="角色分页列表", description="分页查询角色列表"
)
@log(content="角色分页列表", module="角色")
async def get_role_page(
    request: Request,
    current_user: CurrentUserDep,
    role_service: RoleServiceDep,
    page_num: int = Query(1, alias="pageNum", description="页码", ge=1),
    page_size: int = Query(10, alias="pageSize", description="每页记录数", ge=10, le=1000),
    keywords: str = Query(None, alias="keywords", description="关键字(角色名称/角色编码)"),
) -> Response[Pagination[RolePageVO]]:
    """
    角色分页列表
    """
    try:
        roles = [role.code for role in current_user.roles]
        is_root = settings.ADMIN_ROLE_CODE in roles

        result = await role_service.get_role_page(
            keywords=keywords,
            is_root=is_root,
            page_num=page_num,
            page_size=page_size,
        )

        return Response.success(data=result)
    except Exception as e:
        raise AppException(message="获取角色分页列表失败") from e


@router.get(
    "/options",
    response_model=Response[List[IntOption]],
    response_model_exclude_none=True,
    summary="角色下拉列表",
    description="获取所有角色的下拉选项列表",
)
async def list_role_options(
    current_user: CurrentUserDep,
    role_service: RoleServiceDep,
) -> Response[List[IntOption]]:
    """
    角色下拉列表
    """
    try:
        roles = await role_service.get_role_list()
        if not roles:
            return Response.success([])
        return Response.success(data=[IntOption.create_simple(role.id, role.name) for role in roles])
    except Exception as e:
        raise AppException(message="获取角色下拉列表失败") from e


@router.post("", response_model=Response[None], summary="新增角色", description="创建新角色，需 sys:role:add 权限")
@log(content="新增角色", module="角色")
async def add_role(
    request: Request,
    role_service: RoleServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:role:add"))],
    role_form: RoleForm = Body(..., description="角色表单数据"),
) -> Response[None]:
    """
    新增角色
    """
    try:
        await role_service.save_role(role_id=role_form.id, role_form=role_form, user_id=current_user.id)
        return Response.success()
    except Exception as e:
        raise AppException(message="新增角色失败") from e


@router.get(
    "/{role_id}/form",
    response_model=Response[RoleForm],
    summary="获取角色表单数据",
    description="根据角色ID获取编辑表单数据，需 sys:role:edit 权限",
)
@log(content="获取角色表单数据", module="角色")
async def get_role_form(
    request: Request,
    role_service: RoleServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:role:edit"))],
    role_id: int = Path(..., description="角色ID"),
) -> Response[RoleForm]:
    """
    获取角色表单数据
    """
    try:
        role = await role_service.get_role_by_id(role_id=role_id)
        if not role:
            return Response.failed(code="E0404", message="角色不存在")
        return Response.success(data=RoleForm.model_validate(role))
    except Exception as e:
        raise AppException(message="获取角色表单数据失败") from e


@router.put(
    "/{id}", response_model=Response[None], summary="修改角色", description="更新角色信息，需 sys:role:edit 权限"
)
@log(content="修改角色", module="角色")
async def update_role(
    request: Request,
    role_service: RoleServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:role:edit"))],
    role_form: RoleForm = Body(..., description="角色表单数据"),
    id: int = Path(..., description="角色ID"),
) -> Response[None]:
    """
    修改角色
    """
    try:
        if role_form.id != id:
            return Response.failed(code="E0400", message="角色ID不匹配")
        await role_service.save_role(role_id=id, role_form=role_form, user_id=current_user.id)
        return Response.success()
    except Exception as e:
        raise AppException(message="修改角色失败") from e


@router.delete(
    "/{ids}",
    response_model=Response[None],
    summary="删除角色",
    description="批量删除角色，多个ID用英文逗号分隔，需 sys:role:delete 权限",
)
@log(content="删除角色", module="角色")
async def delete_roles(
    request: Request,
    role_service: RoleServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:role:delete"))],
    ids: str = Path(..., description="删除角色，多个以英文逗号(,)拼接"),
) -> Response[None]:
    """
    删除角色
    """
    try:
        role_ids = [int(role_id) for role_id in ids.split(",")]
        for role_id in role_ids:
            await role_service.delete_role(role_id=role_id, user_id=current_user.id)
        return Response.success()
    except Exception as e:
        raise AppException(message="删除角色失败") from e


@router.put(
    "/{role_id}/status",
    response_model=Response[None],
    summary="修改角色状态",
    description="启用或禁用角色，需 sys:role:edit 权限",
)
@log(content="修改角色状态", module="角色")
async def update_role_status(
    request: Request,
    role_service: RoleServiceDep,
    current_user: Annotated[SysUser, Depends(require_permission("sys:role:edit"))],
    role_id: int = Path(..., description="角色ID"),
    status: int = Query(..., description="状态(1:启用;0:禁用)"),
) -> Response[None]:
    """
    修改角色状态
    """
    try:
        role_form = RoleForm(id=role_id, status=status)
        await role_service.save_role(role_id=role_id, role_form=role_form, user_id=current_user.id)
        return Response.success()
    except Exception as e:
        raise AppException(message="修改角色状态失败") from e


@router.get(
    "/{role_id}/menuIds",
    response_model=Response[List[int]],
    summary="获取角色的菜单ID集合",
    description="查询指定角色已分配的菜单权限ID列表",
)
async def get_role_menu_ids(
    role_service: RoleServiceDep,
    current_user: CurrentUserDep,
    role_id: int = Path(..., description="角色ID"),
) -> Response[List[int]]:
    """
    获取角色的菜单ID集合
    """
    try:
        # roles = [role.code for role in current_user.roles]
        # is_root = settings.ADMIN_ROLE_CODE in roles

        role = await role_service.get_role_by_id(role_id=role_id)
        if not role:
            return Response.failed(code="E0404", message="角色不存在")
        menu_ids = [menu.id for menu in role.menus]
        return Response.success(data=menu_ids)
    except Exception as e:
        raise AppException(message="获取角色的菜单ID集合失败") from e


@router.put(
    "/{role_id}/menus", response_model=Response[None], summary="角色分配菜单权限", description="为指定角色分配菜单权限"
)
@log(content="角色分配菜单权限", module="角色")
async def assign_menus_to_role(
    request: Request,
    role_service: RoleServiceDep,
    current_user: CurrentUserDep,
    role_id: int = Path(..., description="角色ID"),
    menu_ids: List[int] = Body(..., description="菜单ID列表"),
) -> Response[None]:
    """
    角色分配菜单权限
    """
    try:
        await role_service.assign_role_menus(role_id=role_id, menu_ids=menu_ids)
        return Response.success()
    except Exception as e:
        raise AppException(message="角色分配菜单权限失败") from e
